package com.wiseman.writing.utility;

import java.util.ArrayList;
import java.util.List;

import com.wiseman.writing.ConstValue;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Path.FillType;
import android.view.View;

class Writing implements ConstValue {

	boolean mIsActive;
	boolean mIsStrokeComplete;
	boolean mIsCharComplete;

	int mStrokeIdx;
	int mStepIdx;
	int mPosTolerance = 0;

	final View mView;

	private List<StrokeData> mStrokeList;
	private StrokeData mStroke;
	private Canvas mCanvas;

	private Paint mPaint;

	int mStep = DEFAULT_WRITING_STEP;

	public Writing(View view) {
		mView = view;
		reset();
	}

	void reset() {
		mIsActive = false;
		mStrokeIdx = 0;
		mStepIdx = 0;
		mIsStrokeComplete = false;		
		mIsCharComplete = false;
	}
	
	boolean isCharComplete(){
		return mIsCharComplete;
	}
	
	

	public void handleActionDown(Point pt) {
		
		if (ptInStroke(pt)) {
			drawStep();

			if (mIsActive == false) {
				mIsActive = true;
			}
		}

	}

	public void handleActionMove(Point pt) {
		if (!mIsActive)
			return;
		
		if(mIsStrokeComplete)
			return;

		if (ptInStroke(pt)) {
			drawStep();
		}

	}

	public void handleActionUp(Point pt) {
		if (!mIsActive)
			return;

		if (mIsStrokeComplete) {
			mStrokeIdx++;
			if (mStrokeIdx < mStrokeList.size()) {
				mStroke = mStrokeList.get(mStrokeIdx);
				mIsStrokeComplete = false;
				mStepIdx = 0;
				Util.drawGuideLine(mCanvas, mStroke);
				mView.postInvalidate();
			} else {
				mIsCharComplete = true;
				mStroke = mStrokeList.get(0);
			}
		}else{
			//if current stroke has writing 90%, we consider user has complete it.
			if(mStepIdx  >= mStroke.m_posList.size() * 0.85){
				while(!mIsStrokeComplete){
					drawStep();
				}
			}
		}

	}

	private void drawStep() {	
		
		ArrayList<Point> posList = mStroke.m_posList;
		ArrayList<Point> negList = mStroke.m_negList;

		Path path = new Path();		
		
		int endIndex = mStepIdx + mStep;
		
		if(endIndex > posList.size() - 1){
			endIndex = posList.size() - 1;
		}
		

		Path path1 = Util.createPathByPoints(posList, 0, endIndex, null);
		path.addPath(path1);
		Path path2 = Util.createPathByPoints(negList, 0, endIndex, null);
		path.addPath(path2);

		// join start and end point.
		Point p = posList.get(endIndex);
		path.lineTo(p.x, p.y);

		path.setFillType(FillType.EVEN_ODD);
		mCanvas.drawPath(path, mPaint);

		mView.postInvalidate();

		mStepIdx += mStep;
		
		if (mStepIdx > posList.size() - 1) {		
			mIsStrokeComplete = true;
		}		
	}

	private boolean ptInStroke(Point pt) {
		boolean ret = false;

		ArrayList<Point> posList = mStroke.m_posList;
		ArrayList<Point> negList = mStroke.m_negList;
		Point min = new Point();
		Point max = new Point();
		
		if(mStepIdx > posList.size() - 1){
			return false;
		}

		min.set(posList.get(mStepIdx).x, posList.get(mStepIdx).y);
		max.set(posList.get(mStepIdx).x, posList.get(mStepIdx).y);

		for (int i = 0; i < mStep; i++) {
			int index = mStepIdx + i;
			if(index > posList.size() - 1){
				break;
			}
			Util.checkBoundValue(min, max, posList.get(index));
			Util.checkBoundValue(min, max, negList.get(index));
		}

		Rect rt = new Rect(min.x, min.y, max.x, max.y);

		rt.left -= mPosTolerance;
		rt.top -= mPosTolerance;
		rt.right += mPosTolerance;
		rt.bottom += mPosTolerance;

		ret = Util.ptInRect(pt, rt);

		return ret;
	}
	
	public boolean isStartWrite(Point pt) {
		boolean ret = false;

		ArrayList<Point> posList = mStrokeList.get(0).m_posList;
		ArrayList<Point> negList = mStrokeList.get(0).m_negList;
		Point min = new Point();
		Point max = new Point();
		
		min.set(posList.get(0).x, posList.get(0).y);
		max.set(posList.get(0).x, posList.get(0).y);

		for (int i = 0; i < mStep; i++) {
			int index = i;
			if(index > posList.size() - 1){
				break;
			}
			Util.checkBoundValue(min, max, posList.get(index));
			Util.checkBoundValue(min, max, negList.get(index));
		}

		Rect rt = new Rect(min.x, min.y, max.x, max.y);

		rt.left -= mPosTolerance;
		rt.top -= mPosTolerance;
		rt.right += mPosTolerance;
		rt.bottom += mPosTolerance;

		ret = Util.ptInRect(pt, rt);

		return ret;
	}

	public void setData(List<StrokeData> dataList, Canvas canvas, Paint paint) {
		mStrokeList = dataList;
		mStroke = mStrokeList.get(0);
		mCanvas = canvas;
		mPaint = paint;
	}
	
	public void setWritingSensivity(int sensivity){
		mPosTolerance = 10*(1+sensivity);
		mStep = DEFAULT_WRITING_STEP *(1+sensivity/2);	
	}
};